﻿//console.debug(jkui.all ([1, 0], function(i, x){return this - 1 >= 1;}));

//debug

if (typeof console == 'undefined') {
	console = {};
	console.debug = function (message) {alert (message);}
}

if (!console.debug) {
	console.debug = function (message) {alert (message);}
}

(function($, $$){
	var undefined;
	
	$$.object = $$.extend($$, function(o, parent){
		this._parent = parent;
		this.children = [];
		
		this.type = 'object';
		
		var defaults = {
			name: ''
		};

		this.props = $.extend(defaults, o);
		this.Super();
		
		//implements jQuery "data" function equivalent
		var data = {};
		//this is how to write a "final" function
		this.data = function(n, d) {
			if (arguments.length == 1) return data[n];
			else if (arguments.length == 2) data[n] = d;
			
			return this;
		};
		
		$$.object._insertChild (parent, this);
	});
	
	//those events shouldn't be propagated to the parent
	$$.object.PropergateEvents = {
		destroying: false,
		destroyed: false
	};
	
	$$.object.prototype.parent = function(p) {
		//getter
		if (!arguments.length) return this._parent;
		
		//setter
		if (typeof p == 'object' && p instanceof $$.object &&
			$$.object._deleteChild (this._parent, this) && 
			 $$.object._insertChild (p, this) && 
				(this._parent = p)){
					return this;
				}
	};
	
	$$.object.prototype.name = function(n) {
		//getter
		if (!arguments.length) return this.props.name;
		
		//setter
		this.props.name = n;
		return this;
	}
	
	$$.object.prototype.destroy = function(){
		//chaining of destructor to remove all children when removing a parent
		
		while (this.children.length)
			this.children[0].destroy();
		
		$$.object._deleteChild (this._parent, this);
		
		console.debug('object destroy');
	};
	
	$$.object._deleteChild = function (parent, child) {
		//remove itself from the parent's children list
		if (parent instanceof $$.object && child instanceof $$.object) {
			for (var i = 0; i < parent.children.length; i++) {
				if (parent.children[i] == child)
					parent.children.splice(i, 1);
			}
		}
		return true;
	};
	
	$$.object._insertChild = function (parent, child) {
		if (typeof parent == 'object' && parent instanceof $$.object && 
			typeof parent.children == 'object' && parent.children instanceof Array) {
			parent.children.push(child);
			return true;
		}
		return false;
	};
	
	$$.object.prototype.trigger = function(name) {
		var tmp = $$.prototype.trigger.apply(this, arguments);
	
		if (tmp && typeof this._parent == 'object' && this._parent instanceof $$.object &&
			$$.object.PropergateEvents[name] !== false) {
			this._parent.trigger.apply(this._parent, arguments);
		}
		
		return tmp;
	};
	
	$$.widget = $$.abstractExtend($$.object, function(o, parent){
	//	console.debug('initing widget');
		
		var defaults = {
			dom: '<div>',
			className: '',
			x: undefined,
			y: undefined,
			w: undefined,
			h: 'auto'
		};
		this.Super($.extend(defaults, o), parent);
		
		this._parent = this._parent? this._parent : 'body';
		this.type = 'widget';
		
		this._dom = $(this.props.dom);
		
		var eventsList = 'focus blur click mouseover mouseout mouseenter mouseleave mousedown mouseup keydown keyup keypress resize'.split(' ');
		this.bind (defaults, eventsList).bind(defaults, 'loading loaded hiding hidden showing shown'.split(' '));
		
		//setup DOM events
		$$.each(eventsList, function(i, THIS){
			var handler = THIS._genDefaultHandler(this);
			THIS._dom.unbind(this, handler).bind(this, handler);
		}, this);
			
		this.addClass(defaults.className);
	});
	
	$$.widget.prototype.addClass = function (className) {
		return this.changeClass(className);
	}
	
	$$.widget.prototype.removeClass = function (className) {
		return this.changeClass(className, true);
	}
	
	$$.widget.prototype.changeClass = function (className, remove) {
		if (typeof className == 'object' && className instanceof Array)
			$$.each(className, function(i, me){
				remove ? me._dom.removeClass(this) : me._dom.addClass(this);
			}, this);
		else if (typeof className == 'string')
			this.changeClass (className.split(' '), remove);
		
		return this;
	}
	
	$$.widget.prototype.dom = function () {
		if (arguments.length) this._dom.replace(arguments[0]);
		else return this._dom;
		
		return this;
	}
	
	$$.widget.prototype._addDomChildren = function (elem, domParent) {
		
		!elem instanceof Array && (elem = [elem]);
		
		domParent = domParent !== undefined ? domParent : this._parent;
		
		if (domParent && domParent instanceof $$.widget){
			$$.each(elem, function(i) {
				domParent._dom.append(this);
			});
		}
		else if (domParent instanceof $)
			$$.each(elem, function(i) {
				domParent.append(this);
			});
		else if (!domParent)
			$$.each(elem, function(i) {
				$('body').append(this);
			});
		else if ($(domParent).length) 
			$$.each(elem, function(i) {
				$(domParent).append(this);
			});
			
	}
	
	$$.widget.prototype.offset = function(){
		return {x: this.props.x, y: this.props.y};
	}
	
	$$.widget.prototype.x = function(x){
		if (x === undefined) return this.props.x;
		this.props.x = x;
		
		return this;
	}
	
	$$.widget.prototype.y = function(y){
		if (y === undefined) return this.props.y;
		this.props.y = y;
		
		return this;
	}
	
	//@ virtual protected member functions
	$$.widget.prototype._load = function () {
		this._addDomChildren(this._dom);
	}
	
	$$.widget.prototype._show = function () {
		this._dom.show();
	}
	
	$$.widget.prototype._hide = function () {
		this._dom.hide();
	}
	
	$$.widget.prototype.load = function (){
		if (this.trigger('loading') && !this.isLoaded) {
			
			this._load();
			this._dom.hide();
			
			this.isHidden = true;
			this.isLoaded = true;
			this.trigger('loaded');
		}
		
		return this;
	}
	
	$$.widget.prototype.hide = function (){
		if (this.trigger('hiding') && !this.isHidden) {
			
			this._hide();
			
			this.isHidden = true;
			this.trigger('hidden');
		}
		return this;
	}
	
	$$.widget.prototype.show = function (){
		if (this.trigger('showing') && this.isHidden) {
			
			this._show();
			
			this.isHidden = false;
			this.trigger('shown');
		}
		
		return this;
	}
	
	$$.widget.prototype.destroy = function() {
		$(this._dom).remove();
		console.debug('widget destroy');
	};

	/*
		class button		***
	*/
	
	$$.button = $$.extend($$.widget, function(o, parent){
	
		var defaults = {
			dom: '<button jkuiType="button"><span></span></button>',
			text: 'OK',
			className: 'jkui-btn'
		};
		
		this.Super($.extend(defaults, o), parent);
		this.build();
		this.type = 'button';
	});
	
	$$.button.prototype.destroy = function() {
		console.debug('button destroy');
	};
	
	$$.button.prototype.clickHandler = function(e){
		return this.trigger('click', e);
	};
	
	$$.button.prototype.build = function(){
		this.text(this.props.text);
		return this;
	};
	
	$$.button.prototype.text = function(t){
		if (arguments.length) {
			this.props.text = t;
			this._dom.find('span').html(t);
		}
		else return this.props.text;
		
		return this;
	};
	
	$$.button.prototype.disable = function() {
		$(this._dom).attr('disabled', 'disabled');
		return this;
	};
	
	$$.button.prototype.enable = function() {
		this._dom.removeAttr('disabled');
		return this;
	};
	
	$$.button.prototype.destroy = function() {
		console.debug('button destroy');
	}
	
	/*
		class window		***
	*/
	
	$$.window = $$.extend ($$.widget, function(o, parent){
		var defaults = {
			dom: '<div jkuiType="window">',
			modal: false,
			morphStart: null,
			position: 'auto',
			text: '',
			content: '',
			className: 'jkui-window'
		};
		defaults = $.extend(defaults, o);
		this.Super(defaults, parent);
		
		this.type = 'window';
		
		this.build();
	});
	
	$$.window.prototype.onFocus = function(e) {
		this._dom.blur();
		
		if ($$.window.topWindow == this || !this.trigger('focus', e))
			return;
			
		$$.window.topWindow = this;
		
		this._removeFromWindowList() && $$.window.list.push (this);
		
		$$.window.reAssignZIndex();
		
		return false;
	}
	
	$$.window.prototype.destroy = function(){
		$(this.overlay).remove();
		this._removeFromWindowList();
	};
	
	$$.window.prototype.build = function() {
		this._dom.attr('tabIndex', $$.window.currentTabIndex++);
		var background = $('<div jkuiType="windowBackground" class="jkui-window-background">');
		this._dom.append(background).append('<div class="jkui-window-foreground" jkuiType="windowForeground">');
		
		this._dom.find('[jkuiType=windowForeground]')
				.append($('<h3 jkuiType="title" class="jkui-window-title"><span>'+this.props.text+'</span></h3><div class="jkui-window-content" jkuiType="content"></div>'))
				.find('div[jkuiType=content]').append(this.props.content);
		
		this.overlay = $('<div class="jkui-window-overlay">').height($(document).height()).click($$.bind(this.hide, this)).hide();
		this._dom.css({
			position: 'absolute',
			overflow: 'hidden'
		});
		background.css({position: 'absolute', zIndex:-1})
					.click($$.bind(this.onFocus, this));
		
		this._dom.find('*').focus($$.bind(this.onFocus, this));
		
		//assign events for window's drag & drop	
		var THIS = this;
		
		this._dom.find('[jkuiType=title]').mousedown (function(e) {
			
			if (e.button != 1 && $.browser.msie || e.button && !$.browser.msie) return;
			
			//cancel IE's dragging select when moving the window
			$(document).bind('selectstart', $$.window.cancelIEOnSelect);
			
			THIS.mouseX = e.clientX;
			THIS.mouseY = e.clientY;
			THIS.startX = THIS.x();
			THIS.startY = THIS.y();
			
			$$.window.currentDragging = THIS;
			THIS.onFocus();
			
			this.setCapture && this.setCapture();
			
			return false;
		});
		
		return this;
	};
	
	$$.window.prototype._load = function(){
		//exception case: 
		if (this.props.modal)
			this._addDomChildren([this.overlay, this._dom], null);
		else
			this._addDomChildren(this._dom, null);
	};
	
	$$.window.prototype._show = function(){
		if (this.props.modal) {
			for (var i = 0; i < $$.window.list.length; i++) {
				if ($$.window.list[i].parent === this._parent) 
					return this;
			}
		}
		
		this._dom.show();
		this.overlay.show();
		this.adjustGeometry();
		
		$$.window.list.push(this);
		$$.window.reAssignZIndex();
	};
	
	$$.window.prototype._hide = function(){
		this._dom.hide();
		this.overlay.hide();
		
		this._removeFromWindowList();
	};
	
	//if this window is in the widnow list, return true otherwise return false
	$$.window.prototype._removeFromWindowList = function(){
		for (var i = 0; i < $$.window.list.length; i++) {
			if ($$.window.list[i] === this) {
			
				//remove the window to the end of the list
				$$.window.list.splice(i, 1);
				return true;
			}
		}
		return false;
	};
	
	$$.window.prototype.adjustGeometry = function(type) {
		if (!this.isLoaded) return this;
		
		if (this.props.w === undefined || this.props.x === undefined || this.props.y === undefined) {
			var halfWidth = ($('body').width() - 20) / 2;
			var halfHeight = ($(window).height() - 20) / 2;
			
			this.props.w = this.props.w === undefined? halfWidth : this.props.w;
			
			if (this.props.h == 'auto')
				this.props.heightPolicy = 'auto';
			if (this.props.heightPolicy == 'auto')
				this.props.h = this._dom.width(this.props.w).height();
			
			this.props.h = this.props.h === undefined ? halfHeight : this.props.h;
		
			switch (this.props.position) {
				case 'center':
					this.props.x = halfWidth - this.props.w / 2;
					this.props.y = $(document).scrollTop() + halfHeight - this.props.h / 2;
					break;
				case 'auto':
					$$.window.lastWindowPos.x = ($$.window.lastWindowPos.x + 30) % (halfWidth / 3);
					this.props.x = $$.window.lastWindowPos.x + halfWidth / 3;
					$$.window.lastWindowPos.y = ($$.window.lastWindowPos.y + 30) % (halfHeight / 3);
					this.props.y = $$.window.lastWindowPos.y + halfHeight / 3;
				default:
					break;
			}
		}
		
		if (this.props.heightPolicy == 'auto'){
			this._dom.css('height', 'auto');
			this.props.h = this._dom.width(this.props.w).height();
		}
		
		this._dom.css({
			left: this.props.x,
			top: this.props.y
		});
		
		if (type != 'move') {
			this._dom.css({
				width: this.props.w,
				height: this.props.h
			});
			
			this._dom.children('[jkuiType=windowBackground]').css({
				width: this.props.w-2,
				height: this.props.h-2
			});
		}
		return this;
	};
	
	$$.window.prototype.moveBy = function (dx, dy) {
		this.props.x += dx;
		this.props.y += dy;
		this.adjustGeometry('move');
	}
	
	$$.window.prototype.moveTo = function (x, y) {
		this.props.x = x;
		this.props.y = y;
		this.adjustGeometry('move');
	}
	
	$$.window.prototype.depth = function(depth) {
		if (depth === undefined)	return this._dom.css('zIndex');
		
	//	console.log(this.props.text, ' ', this._dom.css('zIndex'), ' ', depth);
		
	//	setTimeout($$.bind(function() {
			this.overlay.css('zIndex', depth - 1);
			this._dom.css('zIndex', depth);
	//	},this),1);
		
	//	console.log(this._dom.find('h3').html(), ' after ', this._dom.css('zIndex'), ' ', this.background.css('zIndex'));
		
		return this;
	};
	
	$$.window.lastWindowPos = {x: 0, y: 0};
	$$.window.baseZIndex = 1000;
	$$.window.currentTabIndex = 10;
	$$.window.list = [];
	$$.window.reAssignZIndex = function() {
		$$.each($$.window.list, function(i){
	//		console.log(i);
			this.depth($$.window.baseZIndex + i * 3 + 2);
		});
	};
	$$.window.currentDragging = (function(){
		$(document).mouseup(function(e){
			if ($$.window.currentDragging) {
				$$.window.currentDragging = null;
				$(document).unbind('selectstart', $$.window.cancelIEOnSelect);
				this.releaseCapture && this.releaseCapture();
			}
		}).mousemove(function(e){
			if ($$.window.currentDragging) {
			//	console.debug($$.window.currentDragging);
				$$.window.currentDragging.moveTo (
					e.clientX - $$.window.currentDragging.mouseX + $$.window.currentDragging.startX, 
					e.clientY - $$.window.currentDragging.mouseY + $$.window.currentDragging.startY
				);
				return false;
			}
		});
		return null;
	})();
	$$.window.cancelIEOnSelect = function(){return false;}
	
	
	/*
		class button group
	*/
	
	$$.buttonGroup = $$.extend ($$.widget, function(o, parent){
		var defaults = {
			dom: '<ul jkuiType="buttonGroup">',
			position: 'center',
			exclusive: true,
			className: 'jkui-buttongroup'
		};
		
		this.Super($.extend(defaults, o), parent);
		this.type = 'buttonGroup';
		this.position(this.props.position);
	});
	
	$$.buttonGroup.prototype.addButton = function(button){
		if (typeof button == 'object' && button instanceof Array)
			$$.each(button, function(i, me, btn){
				this.addButton(btn);
			}, this);
		
		if (typeof button == 'object' && button instanceof $$.button) {
			this._dom.append($('<li>').appendTo(this._dom).append(button.dom()));
			button.parent(this);
		}
		
		return this;
	};
	
	$$.buttonGroup.prototype.position = function(p){
		//getter
		if (!arguments.length) return this.props.position;
		
		//setter
		p += '';	//try to convert p to string
		if (p == 'center' || p == 'left' || p == 'right') {
			this._dom.removeClass('jkui-buttongroup-'+this.props.position).addClass('jkui-buttongroup-'+p);
			this.props.position = p;
		}
		return this;
	};
	
	$$.buttonGroup.prototype.adjustGeometry = function(){
		var totalWidth = 0;
		this._dom.find('li').each(function(){
			totalWidth += $(this).width () + 6;
		});
		this._dom.width(totalWidth + 5);
		
		return this;
	}
	
	$$.buttonGroup.prototype.destroy = function(){
		console.debug('buttonGroup destroy');
	};
	
	/*
		class dialog		***
	*/
	
	$$.dialog = $$.extend($$.window, function(o, parent){
		var defaults = {
			dom: '<div jkuiType="dialog">',
			w: 500,
			position: 'center',
			modal: true,
			buttonsAlign: 'right',
			defaultButtons: true,
			buttons: [],
			okText: 'OK',
			cancelText: 'cancel'
		};
		defaults = $.extend(defaults, o)

		defaults.defaultButtons && (defaults.buttons = [$$.button({
				text: defaults.okText,
				className: 'jkui-btn jkui-btn-ok'
			}),
			$$.button({
				text: defaults.cancelText,
				className: 'jkui-btn jkui-btn-cancel'
			})].concat(defaults.buttons || [])
		);
		
		this.Super(defaults, parent);
		this.type = 'dialog';
		
		this.bind(defaults, 'cancel ok'.split(' '));
	});
	
	$$.dialog.prototype.build = function() {
		$$.window.prototype.build.call(this);
		this.btnGroup = $$.buttonGroup({position: this.props.buttonsAlign},this);
		
		$$.each(this.props.buttons, function(i, THIS){
			THIS.addButton(this);
		}, this);
		this.btnGroup.dom().insertAfter(this._dom.find('[jkuiType=content]'));
	}
	
	$$.dialog.prototype.addButton = function(button){
		button.bind('click', $$.bind(function(){
			this.trigger(button.name());
		}, this));
		this.btnGroup.addButton(button);
		return this;
	};
	
	$$.dialog.prototype.buttons = function(){
		return this.btnGroup.children;
	};
	
	$$.dialog.prototype.adjustGeometry = function(){
		if (!this.isLoaded) return this;
		
		this.btnGroup.adjustGeometry();
		$$.window.prototype.adjustGeometry.apply(this, arguments);
		
		return this;
	};
	
	$$.dialog.prototype.destroy = function() {
		console.debug('dialog destroy');
	};
	
	/*
		class fancyDialog		***
	*/
	
	$$.fancyDialog = $$.extend ($$.dialog, function(o, parent){
		this.Super(o, parent);
		this.type = 'fancyDialog';
	}, $$.asyncronized, $$.fancyWindow);
	
	delete $$.fancyDialog.prototype.load;
	delete $$.fancyDialog.prototype._load;
	
	/*
		class tabDialog		***
	*/
	
	$$.tabDialog = $$.extend($$.dialog, function(o, parent){
		this.Super(o, parent);
		this.type = 'tabDialog';
		this.bind('contentchanged', function(){
			this.adjustGeometry();
		});
	}, $$.tabs);
	
	/*
		class fancyTabDialog		***
	*/
	
	$$.fancyTabDialog = $$.extend ($$.tabDialog, function(o, parent){
		this.Super(o, parent);
		this.type = 'fancyTabDialog';
	}, $$.asyncronized, $$.fancyWindow);
	
	delete $$.fancyTabDialog.prototype.load;
	delete $$.fancyTabDialog.prototype._load;
	
	/*
		c = new $$.dialog({
			text: 'ABCD',
	//		modal: true,
			content: $('#components .editor').clone(true, true)
		}, d);
		c.bind('destroying', function(){
			console.debug(2);
		});
		c.load().show().adjustGeometry();
		
	//	c = c.destroy();*/
	//	d = d.destroy();
	//	console.debug($$.dialog.prototype.destroy.pure.toString());
	
})(jQuery, jkui);
